/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.mavenrentcars.service.impl;

import com.mavenrentcars.dao.AccountDao;
import com.mavenrentcars.exception.ViewException;
import com.mavenrentcars.form.AccountForm;
import com.mavenrentcars.model.User;
import com.mavenrentcars.model.Role;
import com.mavenrentcars.service.AccountService;
import com.mavenrentcars.service.RoleService;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import org.springframework.dao.DataAccessException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

/**
 *
 * @author student
 */
@Service("accountService")
public class AccountServiceImpl implements AccountService {

    private final String error1 = "You can not get Model before you created it. Run Post in first.";
    @Resource(name = "accountDao")
    private AccountDao accountDao;
    @Resource(name = "roleService")
    private RoleService roleService;

    @Override
    public User save(User model) throws ViewException {
        return accountDao.save(model);
    }

    @Override
    public User get(Integer id) throws ViewException {
        return accountDao.get(id);
    }

    @Override
    public void remove(Integer id) throws ViewException {
        accountDao.remove(id);
    }

    @Override
    public List<User> getAll() throws ViewException {
        return accountDao.getAll();
    }

    @Override
    public User saveAccount(AccountForm form) throws ViewException {
        User item;
        if (!form.getId().equals("")) {
            item = accountDao.get(Integer.parseInt(form.getId()));
        } else {
            item = new User();
        }
        item.setEmail(form.getEmail());
        item.setUserName(form.getName());
        item.setPhone(2);
        item.setGender(form.getGender());
        item.setAddress(form.getAddress());
        item.setDriveCategory(form.getDriveCategory());
        item.setDriveLength(Integer.parseInt(form.getDriveLength()));

        User account = accountDao.save(item);
        this.setRoles(account, form.getRoles());

        return account;
    }

    /*
     * 
     */
    @Override
    public boolean hasRole(ArrayList<String> roles) {
        try {
            Collection<GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();

            for (GrantedAuthority auth : authorities) {
                for (String role : roles) {
                    if (auth.getAuthority().equals(role)) {
                        return true;
                    }
                }
            }
        } catch (NullPointerException e) {
        }

        return false;
    }

    @Override
    public boolean hasOneRole(String role) {
        ArrayList<String> roles = new ArrayList<String>();
        roles.add(role);
        return hasRole(roles);
    }

    public void removeOldRoles(User account) throws ViewException {
        //remove old roles
        List<Role> roles = roleService.getByAccount(account);
        if (roles != null) {
            for (Role ritem : roles) {
                roleService.remove(ritem.getId());
            }
        }
    }

    public void setRoles(User account, Map<String, String> rmap) {
        try {

            Logger.getLogger(AccountServiceImpl.class.getName()).info("INIT ");
            Set<Role> roles = new HashSet<Role>();
            for (Entry<String, String> entry : rmap.entrySet()) {
                String key = entry.getKey();
                Logger.getLogger(AccountServiceImpl.class.getName()).info("KEY " + key);
                //lnk role to user
                Role role = roleService.get(Integer.parseInt(key));
                Logger.getLogger(AccountServiceImpl.class.getName()).info("NAME " + role.getRoleName());
                roles.add(role);
            }

            account.setRoles(roles);
            accountDao.save(account);

            //save(account);
        } catch (ViewException ex) {
            Logger.getLogger(AccountServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void setRole(User account, String roleName) {
        try {
            //remove old roles
            this.removeOldRoles(account);

            //add new role
            Role role = new Role();
            role.setRoleName(roleName);
            role.setUser(account);
            role = roleService.save(role);

            //add role to account
            Set<Role> roles = new HashSet<Role>();
            roles.add(role);
            account.setRoles(roles);
            accountDao.save(account);
            //save(account);
        } catch (ViewException ex) {
            Logger.getLogger(AccountServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public String getRole() {
        try {
            List<GrantedAuthority> authorities =
                    (List<GrantedAuthority>) SecurityContextHolder.getContext().
                    getAuthentication().getAuthorities();
            if (authorities.isEmpty()) {
                return "guest";
            } else {
                return authorities.get(0).getAuthority();
            }
        } catch (Exception ex) {
            return "guest";
        }
    }

    /*
     * 
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
        return getAccountByLogin(username);
    }

    /*
     * 
     */
    @Override
    public User setAuthentication(String user, String password, Collection<GrantedAuthority> authorities) {
        SecurityContextHolder.getContext().setAuthentication(
                new UsernamePasswordAuthenticationToken(user, password, authorities));
        return null;
    }

    /*
     * 
     */
    @Override
    public User getLoggedInAccount() {
        User account = null;

        try {
            Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            String username = "";

            if (principal instanceof UserDetails) {
                username = ((UserDetails) principal).getUsername();
            } else {
                username = principal.toString();
            }

            account = this.getAccountByLogin(username);
            return account;

        } catch (ClassCastException cce) {
            return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        } catch (NullPointerException ex) {
            return null;
        }
    }

    @Override
    public User getAccountByLogin(String login) {
        User account = accountDao.getAccountByLogin(login);
        return account;
    }

    @Override
    public void logout() {
        SecurityContextHolder.getContext().setAuthentication(null);
    }
}
